(defun primep(n)
  (cond 
    ((< n 0) (primep (- n)))
    ((<= n 3) t)
    ((zerop (mod n 2)) nil)
    (t (loop 
	  for i = 3 then (+ 2 i) 
	  with lim = (sqrt n) 
	  while (<= i lim) 
	  when (zerop (mod n i)) do (return nil) 
	  finally (return t)))))

(defun digits(n)
  (loop for i = n then (floor (/ i 10))
       while (> i 0)
       collect (mod i 10)))

(defun make-no(l)
  (if (null l) 0 (+ (car l) (* 10 (make-no (cdr l))))))


#|(defun like(a b)
  (loop for i in a
     for j in b
     ;for k in (digits c)
     collect (if (= i j) 1 0)))|#

#|(defun match(a b)
  (loop for i in (digits a) for j in (digits b) 
       with hits = 0 with miss = 0
       do (if (= i j) (incf hits) (incf miss))
       finally (return (and (> hits 2) (<= miss 2)))))|#

(defun row-match (patt)
  (loop for i in (cdr patt)
     when (/= (caar patt) (car i)) do (return nil)
     finally (return T)))

(defun list-match (l)
  (if (null (car l)) nil
      (cons (row-match l) (list-match (mapcar #'cdr l)))))

(defun check-matches (number pattern)
  (loop for i in number
     for j in pattern
     with dig = -1
     when (and (/= dig -1) (not j) (/= i dig))
     do (return nil)
     when (and (= dig -1) (not j))
     do (setq dig i)
     finally (return t)))

(defun match(params)
  (let ((pattern (list-match params)))
#|    (and 
     (loop for i in pattern
	with hits = 0 with miss = 0 
	do (if i (incf hits) (incf miss))
	finally (return (and (> hits 2) (<= miss 2))))|#
     (loop for i in params when (not (check-matches i pattern)) do (return nil) finally (return t))))

(defun pattern(a b)
  (loop for i in a for j in b collect (= i j)))

(defun smart-pattern(a b)
  (loop for i in a 
     for j in b 
     with res = nil 
     do (if (= i j) (setf res (cons i res)) (setf res (cons nil res)))
     finally (return (nreverse res))))

(defun smart-make-no(l dig)
  (if (null l) 0 (+ 
		  (if (null (car l)) dig (car l))
		  (* 10 (smart-make-no (cdr l) dig)))))

(defun test-has-primes(pattern primes)
  (loop for i from 0 to 9 
     for no = (smart-make-no pattern i) 
     with p = 0 with np = 0
     when (> np (- 10 primes)) do (return nil)
     when (= p primes) do (return t)
     do (if (primep no) (incf p) (incf np))))
       

(defun test-pattern(p)
  (loop for i from 0 to 9 for no = (smart-make-no p i) count (primep no)))

(defun find-primes-group(target l1 &optional (l2 (cdr l1)))
  (cond ((null l1) nil)
	((null l2) (find-primes-group target (cdr l1) (cddr l1)))
	((test-has-primes (smart-pattern (car l1) (car l2)) target) (smart-pattern (car l1) (car l2)))
	(t (find-primes-group target l1 (cdr l2) ))))

;  (loop for i from 0 to (- (length primes) 2) do
 ;      (loop for j from i to (1- (length primes)) 
	;  when (= (test-pattern (smart-pattern (elt primes i) (elt primes j))) target) 
	 ; do (print (cons (make-no (elt primes i)) (make-no (elt primes j)))))))


;(defun match-pattern (a b pat)
;  (loop for i in (digits a) for j in (digits b) for k in pat with carry = -1
       

(defun my-search-inner (a b c)		
  (let ((na (car a)) (nb (car b)))
    (cond ((= (length c) 4) (print c))
	  ((null (cdr b)) (my-search-inner (cdr a) (cddr a) nil))
	  ((null (cdr a)) (print "none found"))
	  ((not (match (list na nb))) (my-search-inner a (cdr b) c))
	  ((match (cons na (cons nb c)))
	   (my-search-inner a (cdr b) (cons nb c) )
	   (my-search-inner a (cdr b) c))
					;((and (null c) (match (list na nb))))
	  (t (my-search-inner a (cdr b) c)))))

(defun my-search(list)
  (my-search-inner list (cdr list) nil))

(defun s-collect(list)
  (loop  with matches = nil 
     for i in list do (loop for j from 0 to (1- (length  matches))
			 when (match (cons i (elt matches j))) 
			 do (and (setf (elt matches j) (cons i (elt matches j))) (setf matches (cons (elt matches j) matches)))
			 finally (setf matches (cons (list i) matches)))
     finally (return matches)))


(defun tri-collect(list)
  (loop with matches = nil
     for i from 0 to (- (length  list) 3)
     do (loop for j from (1+ i) to (- (length list) 2)
	   do (loop for k from (1+ j) to (1- (length list))
		 when (match (list (nth i list) (nth j list) (nth k list)))
		 do (setf matches (cons (list (nth i list) (nth j list) (nth k list)) matches))))
     finally (return matches)))

(defun contains(x list)
  (loop for i in list 
       when (equal x i) do (return t)
       finally (return nil)))

(defun all-collect(primes)
  (loop with all = (tri-collect primes)
     for x in all
     do (loop for i in primes 
	   when (and (not (contains i  x)) (match (cons i x))) 
	   do (nconc x (list i)))
     finally (return all)))

(defvar *primes* (loop for i from 10000 to 99999 when (primep i) collect (digits i)))

